package com.zy.je.common.core.utils.lang;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;

/**
 * @author zy
 */
@Slf4j
public class MapTypeConverter {

    private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>(Arrays.asList(
            String.class, Integer.class, int.class, Long.class, long.class,
            Double.class, double.class, Float.class, float.class, Short.class, short.class,
            Boolean.class, boolean.class, Byte.class, byte.class, Character.class, char.class,
            BigDecimal.class, BigInteger.class, Date.class, LocalDate.class, LocalDateTime.class
    ));

    /**
     * 从Map中获取值并转换为目标类型
     *
     * @param map 数据源Map
     * @param key 字段键
     * @param targetType 目标类型Class
     * @param <T> 目标类型
     * @return 转换后的值
     * @throws IllegalArgumentException 如果转换失败或不支持的类型
     */
    public static <T> T getValue(Map<?, ?> map, Object key, Class<T> targetType) {
        Object value = map.get(key);

        // 处理空值
        if (value == null) {
            return handleNull(targetType);
        }

        // 已经是目标类型
        if (targetType.isInstance(value)) {
            return targetType.cast(value);
        }

        // 特殊处理数组类型
        if (targetType.isArray()) {
            return convertToArray(value, targetType);
        }

        // 枚举类型处理
        if (targetType.isEnum()) {
            return convertToEnum(value, targetType);
        }

        // 核心类型转换
        return convertValue(value, targetType);
    }

    private static <T> T handleNull(Class<T> targetType) {
        // 基本类型返回默认值
        if (targetType == int.class) {
            return targetType.cast(0);
        }
        if (targetType == long.class) {
            return targetType.cast(0L);
        }
        if (targetType == double.class) {
            return targetType.cast(0.0);
        }
        if (targetType == float.class) {
            return targetType.cast(0.0f);
        }
        if (targetType == short.class) {
            return targetType.cast((short) 0);
        }
        if (targetType == byte.class) {
            return targetType.cast((byte) 0);
        }
        if (targetType == char.class) {
            return targetType.cast('\u0000');
        }
        if (targetType == boolean.class) {
            return targetType.cast(false);
        }

        // 包装类型返回null
        return null;
    }

    @SuppressWarnings("unchecked")
    private static <T> T convertValue(Object value, Class<T> targetType) {
        try {
            // 数字类型转换
            if (Number.class.isAssignableFrom(targetType)) {
                return convertNumber(value, targetType);
            }

            // 字符串类型
            if (targetType == String.class) {
                return targetType.cast(value.toString());
            }

            // 布尔类型
            if (targetType == Boolean.class || targetType == boolean.class) {
                return convertBoolean(value);
            }

            // 日期时间类型
            if (targetType == Date.class) {
                return targetType.cast(convertToDate(value));
            }
            if (targetType == LocalDate.class) {
                return targetType.cast(convertToLocalDate(value));
            }
            if (targetType == LocalDateTime.class) {
                return targetType.cast(convertToLocalDateTime(value));
            }

            // 大数字类型
            if (targetType == BigDecimal.class) {
                return targetType.cast(new BigDecimal(value.toString()));
            }
            if (targetType == BigInteger.class) {
                return targetType.cast(new BigInteger(value.toString()));
            }

            // 字符类型
            if (targetType == Character.class || targetType == char.class) {
                return convertChar(value);
            }

            //其他通过json转换
            log.debug("使用json转换：{}",targetType.getName());
            return JSON.parseObject(JSON.toJSONString(value), targetType);
        } catch (Exception e) {
            throw new IllegalArgumentException("转换失败: " + value + " 到 " + targetType.getName(), e);
        }

//        throw new IllegalArgumentException("不支持的类型: " + targetType.getName());
    }

    // =============== 数字类型转换 ===============
    @SuppressWarnings("unchecked")
    private static <T> T convertNumber(Object value, Class<T> targetType) {
        Number number;

        if (value instanceof Number) {
            number = (Number) value;
        } else {
            // 尝试从字符串解析
            try {
                String strVal = value.toString().trim();
                if (strVal.isEmpty()) {
                    return null;
                }

                // 处理科学计数法
                if (strVal.contains("E") || strVal.contains("e")) {
                    number = new BigDecimal(strVal);
                } else if (strVal.contains(".")) {
                    number = Double.parseDouble(strVal);
                } else {
                    number = new BigInteger(strVal);
                }
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("无法转换为数字: " + value);
            }
        }

        // 目标类型转换
        if (targetType == Integer.class || targetType == int.class) {
            return targetType.cast(number.intValue());
        }
        if (targetType == Long.class || targetType == long.class) {
            return targetType.cast(number.longValue());
        }
        if (targetType == Double.class || targetType == double.class) {
            return targetType.cast(number.doubleValue());
        }
        if (targetType == Float.class || targetType == float.class) {
            return targetType.cast(number.floatValue());
        }
        if (targetType == Short.class || targetType == short.class) {
            return targetType.cast(number.shortValue());
        }
        if (targetType == Byte.class || targetType == byte.class) {
            return targetType.cast(number.byteValue());
        }

        throw new IllegalArgumentException("不支持的数字类型: " + targetType.getName());
    }

    // =============== 布尔类型转换 ===============
    @SuppressWarnings("unchecked")
    private static <T> T convertBoolean(Object value) {
        if (value instanceof Boolean) {
            return (T) value;
        }

        String strVal = value.toString().trim().toLowerCase();

        // 处理常见布尔表示
        if ("true".equals(strVal) || "1".equals(strVal) || "yes".equals(strVal) || "on".equals(strVal)) {
            return (T) Boolean.TRUE;
        }
        if ("false".equals(strVal) || "0".equals(strVal) || "no".equals(strVal) || "off".equals(strVal)) {
            return (T) Boolean.FALSE;
        }

        throw new IllegalArgumentException("无法转换为布尔值: " + value);
    }

    // =============== 字符类型转换 ===============
    @SuppressWarnings("unchecked")
    private static <T> T convertChar(Object value) {
        String str = value.toString();
        if (str.length() == 1) {
            return (T) Character.valueOf(str.charAt(0));
        }
        throw new IllegalArgumentException("无法转换为字符: " + value);
    }

    // =============== 日期时间转换 ===============
    private static Date convertToDate(Object value) {
        if (value instanceof Date) {
            return (Date) value;
        }
        if (value instanceof Number) {
            return new Date(((Number) value).longValue());
        }

        // 尝试解析字符串
        String[] patterns = {
            "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy/MM/dd HH:mm:ss",
            "yyyy/MM/dd", "dd-MM-yyyy", "MM/dd/yyyy"
        };

        String strVal = value.toString().trim();
        for (String pattern : patterns) {
            try {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                LocalDateTime ldt = LocalDateTime.parse(strVal, formatter);
                return Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
            } catch (DateTimeParseException ignored) {
                // 继续尝试下一种格式
            }
        }

        throw new IllegalArgumentException("无法转换为日期: " + value);
    }

    private static LocalDate convertToLocalDate(Object value) {
        if (value instanceof LocalDate) {
            return (LocalDate) value;
        }
        if (value instanceof Number) {
            return Instant.ofEpochMilli(((Number) value).longValue())
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
        }

        String[] patterns = {"yyyy-MM-dd", "yyyy/MM/dd", "dd-MM-yyyy", "MM/dd/yyyy"};
        String strVal = value.toString().trim();

        for (String pattern : patterns) {
            try {
                return LocalDate.parse(strVal, DateTimeFormatter.ofPattern(pattern));
            } catch (DateTimeParseException ignored) {
            }
        }

        throw new IllegalArgumentException("无法转换为LocalDate: " + value);
    }

    private static LocalDateTime convertToLocalDateTime(Object value) {
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        if (value instanceof Number) {
            return Instant.ofEpochMilli(((Number) value).longValue())
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }

        String[] patterns = {
            "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss",
            "yyyy/MM/dd HH:mm:ss", "dd-MM-yyyy HH:mm:ss"
        };

        String strVal = value.toString().trim();
        for (String pattern : patterns) {
            try {
                return LocalDateTime.parse(strVal, DateTimeFormatter.ofPattern(pattern));
            } catch (DateTimeParseException ignored) {
            }
        }

        throw new IllegalArgumentException("无法转换为LocalDateTime: " + value);
    }

    // =============== 数组类型转换 ===============
    @SuppressWarnings("unchecked")
    private static <T> T convertToArray(Object value, Class<T> arrayType) {
        Class<?> componentType = arrayType.getComponentType();

        if (value == null) {
            return null;
        }

        // 已经是数组类型
        if (value.getClass().isArray()) {
            int length = Array.getLength(value);
            Object array = Array.newInstance(componentType, length);

            for (int i = 0; i < length; i++) {
                Object element = Array.get(value, i);
                Array.set(array, i, getValue(Collections.singletonMap("key", element), "key", componentType));
            }
            return arrayType.cast(array);
        }

        // 集合类型
        if (value instanceof Collection) {
            Collection<?> collection = (Collection<?>) value;
            Object array = Array.newInstance(componentType, collection.size());
            int index = 0;

            for (Object element : collection) {
                Array.set(array, index++, getValue(Collections.singletonMap("key", element), "key", componentType));
            }
            return arrayType.cast(array);
        }

        // 单个值转为单元素数组
        Object array = Array.newInstance(componentType, 1);
        Array.set(array, 0, getValue(Collections.singletonMap("key", value), "key", componentType));
        return arrayType.cast(array);
    }

    // =============== 枚举类型转换 ===============
    @SuppressWarnings({"unchecked", "rawtypes"})
    private static <T> T convertToEnum(Object value, Class<T> enumType) {
        if (!enumType.isEnum()) {
            throw new IllegalArgumentException("目标类型不是枚举: " + enumType.getName());
        }

        // 已经是枚举实例
        if (enumType.isInstance(value)) {
            return enumType.cast(value);
        }

        String strVal = value.toString().trim();

        // 尝试按名称匹配
        try {
            return (T) Enum.valueOf((Class<Enum>) enumType, strVal);
        } catch (IllegalArgumentException ignored) {
        }

        // 尝试按ordinal匹配
        try {
            int ordinal = Integer.parseInt(strVal);
            T[] constants = enumType.getEnumConstants();
            if (ordinal >= 0 && ordinal < constants.length) {
                return constants[ordinal];
            }
        } catch (NumberFormatException ignored) {
        }

        // 尝试忽略大小写匹配
        for (T constant : enumType.getEnumConstants()) {
            if (constant.toString().equalsIgnoreCase(strVal)) {
                return constant;
            }
        }

        throw new IllegalArgumentException("无法转换为枚举 " + enumType.getName() + ": " + value);
    }
}
